#pragma once
#include <string>
#include <map>
#include "Eigen/Dense"
#include <vector>
#include <stdio.h>
using namespace std;
using namespace Eigen;
typedef map<string, int> vmap;

class branch
{
public:
    string name = "";
    string from_tag = "";
    string to_tag = "";
    int from_node = 0;
    int to_node = 0;

    double Vbr, Ibr;
    double Gbr, Jbr;

    void set_name(string name)
    {
        this->name = name;
    }

    void set_param(double G, double J = 0)
    {
        Gbr = G;
        Jbr = J;
    }
    void set_tag(string from, string to, vmap Vmap)
    {
        from_tag = from;
        to_tag = to;
        from_node = Vmap[from];
        to_node = Vmap[to];
    }
    void update(Eigen::MatrixXd Vsys) // 把系统电压输入进去
    {
        Vbr = Vsys(from_node) - Vsys(to_node);
        Ibr = Vbr * Gbr + Jbr;
    }
};
class branches
{
public:
    vmap Vmap;
    string name;
    vector<branch> branch_list;
    int operator()(string name)
    {
        for (auto it = branch_list.begin(); it != branch_list.end(); it++)
        {
            if (it->name == name)
                return distance(branch_list.begin(), it); 
        }
        printf("Branch [%s] not found.\n", name.c_str());
        exit(-1);
    }
    branch &operator[](string name)
    {
        for (branch &br : branch_list)
        {
            if (br.name == name)
                return br;
        }
        printf("Branch [%s] not found.\n", name.c_str());
        exit(-1);
    }
    branch &operator[](int index)
    {
        if (index < branch_list.size())
            return branch_list[index];

        printf("Index [%d] out of the size of branch list [%s].\n", index, name.c_str());
        exit(-1);
    }
    void set_name(string name)
    {
        this->name = name;
    }
    void set_map(vmap Vmap)
    {
        this->Vmap = Vmap;
    }
    void add_br(string from_tag, string to_tag, string name = "")
    {
        branch br;
        br.set_tag(from_tag, to_tag, Vmap);
        br.set_name(name);
        branch_list.push_back(br);
    }
    int size()
    {
        return branch_list.size();
    }
    MatrixXd generate_A()
    {
        MatrixXd A(Vmap.size() - 1, size());
        A.setZero();
        for (int i = 0; i < size(); i++)
        {
            branch &br = branch_list[i];

            if (br.from_node != -1)
                A(br.from_node, i) = 1;
            if (br.to_node != -1)
                A(br.to_node, i) = -1;
        }
        return A;
    }
    int get_num_node()
    {
        return Vmap.size();
    }
    int get_num_br()
    {
        return size();
    }
};
